﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Spacer {
	public class Sprite {
		public class SpriteCfg {
			public string Name { get; set; }
			public string TextureName { get; set; }
			public string MaskTextureName { get; set; }
			public Vector2 Center { get; set; }
			public Vector2 Size { get; set; }
			public List<Vector2> Frames { get; set; }
			public List<SpriteSequence.SpriteSequenceCfg> Sequences { get; set; }

			// ----------

			public SpriteCfg() {
				Name = "Sprite";
				TextureName = "Missing";
				MaskTextureName = "Missing";
				Center = Vector2.Zero;
				Size = new Vector2( 1f, 1f );
				Frames = new List<Vector2>();
				Sequences = new List<SpriteSequence.SpriteSequenceCfg>();
			}
		}

		// ----------

		List<Vector2> m_arrFrames;
		Dictionary<string,SpriteSequence> m_dictSequences;

		public string Name { get; private set; }
		public Texture2D Texture { get; private set; }
		public Texture2D MaskTexture { get; private set; }
		public Vector2 Center { get; private set; }
		public Vector2 Size { get; private set; }

		public int Frames {
			get { return m_arrFrames.Count; }
		}

		public int Sequences {
			get { return m_dictSequences.Count; }
		}

		// ----------

		public Sprite( string strName ) {
			Name = strName;

			SpriteCfg cfg = XmlObjectCfg<SpriteCfg>.Load( Configuration.ContentPath + "/Sprites/" + strName + ".xml", null );
			
			// Get texture from the name
			Texture2D buffer;
			if( !Main.Textures.TryGetValue(cfg.TextureName,out buffer) )
				buffer = Main.Textures["Missing"];
			Texture = buffer;
			
			// Get mask texture like above
			if( !Main.Textures.TryGetValue(cfg.MaskTextureName,out buffer) )
				buffer = Main.Textures["Missing"];
			MaskTexture = buffer;

			Center = cfg.Center;
			Size = cfg.Size;
			m_arrFrames = cfg.Frames;
			m_dictSequences = new Dictionary<string,SpriteSequence>();

			foreach(SpriteSequence.SpriteSequenceCfg seqcfg in cfg.Sequences) {
				SpriteSequence seq = new SpriteSequence( seqcfg );
				m_dictSequences[seqcfg.Name] = seq;
			}
		}

		// ----------
		
		public Rectangle GetFrameRect( int index ) {
			Vector2 pos = m_arrFrames[index % m_arrFrames.Count];
			return new Rectangle( (int)pos.X, (int)pos.Y, (int)Size.X, (int)Size.Y );
		}

		public SpriteSequence GetSequence( string index ) {
			if( index == null )
				index = "Idle";

			SpriteSequence ret = null;
			if( !m_dictSequences.TryGetValue(index,out ret) && m_dictSequences.Count > 0 )
				ret = m_dictSequences.First().Value;
			return ret;
		}
	}

	// ----------------------------------------------------------------------------------------------------

	public class SpriteSequence {
		public class SpriteSequenceCfg {
			[CategoryAttribute("General"), DescriptionAttribute("Name of the sequence.")]
			public string Name { get; set; }
			
			[CategoryAttribute("General"), DescriptionAttribute("Frames per second.")]
			public float FrameRate { get; set; }
			
			[CategoryAttribute("General"), DescriptionAttribute("First, inclusive, frame for this sequence.")]
			public int StartFrame { get; set; }
			
			[CategoryAttribute("General"), DescriptionAttribute("Last, inclusive, frame for this sequence.")]
			public int EndFrame { get; set; }
			
			[CategoryAttribute("General"), DescriptionAttribute("Indicates if this sequence loops.")]
			public bool Loop { get; set; }

			// ----------

			public SpriteSequenceCfg() {
				Name = "Idle";
				FrameRate = 0;
				StartFrame = 0;
				EndFrame = 0;
				Loop = false;
			}
		}

		// ----------

		public string Name { get; private set; }
		public float FrameRate { get; private set; }
		public int StartFrame { get; private set; }
		public int EndFrame { get; private set; }
		public bool Loop { get; private set; }

		public int Frames {
			get { return EndFrame - StartFrame + 1; }
		}

		public float Duration {
			get { return (EndFrame-StartFrame+1) / FrameRate; }
		}

		public int GetFrameNumber( float percentage ) {
			return (int)((EndFrame-StartFrame) * (percentage % 1.0f));
		}

		// ----------

		public SpriteSequence() {
			Name = "Idle";
			FrameRate = 0f;
			StartFrame = 1;
			EndFrame = 1;
			Loop = false;
		}

		public SpriteSequence( SpriteSequenceCfg cfg ) {
			Name = cfg.Name;
			FrameRate = cfg.FrameRate;
			StartFrame = cfg.StartFrame;
			EndFrame = cfg.EndFrame;
			Loop = cfg.Loop;
		}
	}
}
